import pandas
import re


class DataFilter(object):
    operatorMapping = {
        "eq": "equal",
        "ne": "not_equal",
        "gt": "greater",
        "ge": "greater_equal",
        "lt": "less",
        "le": "less_equal",
        "in": "inside",
        "ni": "not_inside",
        "lk": "like",
        "nk": "not_like"
    }

    def __init__(self, dataframe, conditions: dict):
        self.conditions = conditions
        self.dataframe = dataframe

    def equal(self, field, value):
        return self.dataframe[field].eq(value)

    def not_equal(self, field, value):
        return ~self.dataframe[field].eq(value)

    def greater(self, field, value):
        return self.dataframe[field].gt(value)

    def greater_equal(self, field, value):
        return self.dataframe[field].ge(value)

    def less(self, field, value):
        return self.dataframe[field].lt(value)

    def less_equal(self, field, value):
        return self.dataframe[field].le(value)

    def inside(self, field, value):
        return self.dataframe[field].isin(value)

    def not_inside(self, field, value):
        return ~self.dataframe[field].isin(value)

    def like(self, field, value):
        return self.dataframe[field].str.contains(value, case=False)

    def not_like(self, field, value):
        return ~self.dataframe[field].str.contains(value, case=False)

    def result(self):
        relationship = None
        for field, items in self.conditions.items():
            if field in self.dataframe.columns:
                for operator, value in items.items():
                    function = getattr(self, self.operatorMapping[operator])
                    if relationship is not None:
                        relationship = relationship & function(field, value)
                    else:
                        relationship = function(field, value)
        if relationship is not None:
            return self.dataframe.loc[relationship]
        else:
            return pandas.DataFrame()


class Leach(object):
    def __init__(self, directory):
        self.directory = directory

    @staticmethod
    def has_digit(value):
        return any(x.isdigit() for x in value)

    def result(self, dataframe, models, market):
        result, temp_df = None, dataframe.copy()
        detail = pandas.read_csv(f"{self.directory}/{market}/detail.csv")
        boards = pandas.DataFrame()
        if "children" in detail.columns:
            boards = detail[~detail["children"].eq(0)]
        temp_df = temp_df.loc[~temp_df["datetime"].eq("0")]
        temp_df["datetime"] = pandas.to_datetime(temp_df["datetime"])
        if market == "stock":
            temp_df["symbol"] = temp_df["symbol"].astype(str).str.zfill(6)
        for item in models:
            temp_df = DataFilter(temp_df, item["params"]).result()
            if item.get("signal"):
                code_ls = list()
                bord_df = boards.loc[boards["symbol"].isin(temp_df["symbol"].values) & boards["sector"].isin(temp_df["sector"].values)]
                for _, row in bord_df.iterrows():
                    children = row.children.strip("[]").split(",")
                    children = [re.sub("\\D", "", symbol) for symbol in children]
                    children = temp_df.loc[temp_df["symbol"].isin(children) & temp_df["sector"].eq("沪深A股")]
                    code_ls.append(children)
                if code_ls:
                    temp_df = pandas.concat(code_ls)
                    temp_df = temp_df.drop_duplicates("symbol")
                else:
                    temp_df = pandas.DataFrame(data=None, columns=temp_df.columns)
            if result is not None:
                result = result.loc[result["symbol"].isin(temp_df["symbol"].values)]
            else:
                result = temp_df
        if result is None:
            return pandas.DataFrame()
        columns = [column for column in result.columns if not self.has_digit(column)]
        return result[columns]
